<?php
namespace app\api\controller;

use app\api\service\PayService;
use app\wechat\model\WechatPaymentRecord;
use app\wechat\service\WechatService;
use think\admin\Exception;
use think\admin\extend\CodeExtend;
use think\facade\Config;
use think\facade\Request;
use think\Response;

class Pay
{
    /**
     * 生成支付签名(pay_sig)
     * @param string $post_body 请求体JSON数据
     * @return string HMAC-SHA256签名 :ml-citation{ref="1,2" data="citationList"}
     */
    public function calcPaySig($uri, string $post_body, $app_key): string
    {
        $temp = $uri . '&' . $post_body;
        return hash_hmac('sha256', $temp, $app_key);
    }

    /**
     * 生成用户态签名(signature)
     * @param string $post_body 请求体JSON数据
     * @param string $session_key 用户会话密钥
     * @return string HMAC-SHA256签名 :ml-citation{ref="1,2" data="citationList"}
     */
    public function calcSignature(string $post_body, string $session_key): string
    {
        return hash_hmac('sha256', $post_body, $session_key);
    }

    /**
     * 构造支付请求
     * @param array $order 订单数据
     * @param string $session_key 当前用户会话密钥
     * @return array 支付请求结果 :ml-citation{ref="1,2" data="citationList"}
     */
    public function createPayment(array $order, string $session_key): array
    {

        $mch_id = Config::get('wechat.wechat_b2b.mch_id');
        $app_key = Config::get('wechat.wechat_b2b.app_key');

        do $pCode = CodeExtend::uniqidNumber(28, 'P');
        while (WechatPaymentRecord::mk()->master()->where(['code' => $pCode])->findOrEmpty()->isExists());
        // 构造请求体
        $post_body=json_encode([
            "mchid"=>$mch_id,//商户号
            "out_trade_no"=>$pCode,//订单号
            "description"=>$order['trade_no'],
            "amount"=>[
                "order_amount"=>intval($order['amount']*100),
                "currency"=>"CNY"
            ],
            "env"=>0  //1  沙箱环境/测试环境 0生产环境/现网环境
        ],JSON_UNESCAPED_UNICODE);

        $paySig = $this->calcPaySig("requestCommonPayment",$post_body,$app_key);
        $signature = $this->calcSignature($post_body,$session_key);
        // 创建支付记录
        $oName = '订单号：'.$order['trade_no'];
        $pAmount = 0;
        static::createPaymentActionB2B($order['openid'], $order['trade_no'], $oName, $order['amount'], 'wechat_xcx', $pCode, strval($pAmount));

        return [
            'signData'=>$post_body,
            'paySig'=>$paySig,
            'signature'=>$signature,
            'mode' => "retail_pay_goods",
        ];

    }

    /**
     * 创建支付行为
     * @param string $openid 用户编号
     * @param string $oCode 订单单号
     * @param string $oName 订单标题
     * @param string $oAmount 订单总金额
     * @param string $pType 支付平台
     * @param string $pCode 子支付单号
     * @param string $pAmount 子支付金额
     * @return array
     * @throws \think\admin\Exception
     */
    protected static function createPaymentActionB2B(string $openid, string $oCode, string $oName, string $oAmount, string $pType, string $pCode, string $pAmount): array
    {
        // 检查是否已经支付
        if (static::withPayedB2B($oCode, $oPayed) >= floatval($oAmount)) {
            throw new Exception("已经完成支付", 1);
        }
        if ($oPayed + floatval($pAmount) > floatval($oAmount)) {
            throw new Exception('总支付超出金额', 0);
        }
        $map = ['order_code' => $oCode, 'payment_status' => 1];
        $model = WechatPaymentRecord::mk()->where($map)->findOrEmpty();
        if ($model->isExists()) throw new Exception("已经完成支付", 1);
        $config = WechatService::getWxconf(true);
        $app_id = Config::get('wechat.wechat_b2b.app_id');
        // 写入订单支付行为
        $model->save([
            'type'         => $pType,
            'code'         => $pCode,
            'appid'        => $app_id,
            'openid'       => $openid,
            'order_code'   => $oCode,
            'order_name'   => $oName,
            'order_amount' => $oAmount,
        ]);
        return $model->toArray();
    }

    /**
     * 获取已支付金额
     * @param string $oCode 原订单单号
     * @param ?float $oPayed 已支付金额[赋值]
     * @return float
     */
    public static function withPayedB2B(string $oCode, ?float &$oPayed = null): float
    {
        $where = ['order_code' => $oCode, 'payment_status' => 1];
        return $oPayed = WechatPaymentRecord::mk()->where($where)->sum('payment_amount');
    }



}